package com.hxh.generater.springBoot.simple.gen;

import com.hxh.config.ApplicationContextUtil;
import com.hxh.entity.Project;
import com.hxh.entity.ProjectDatasource;
import com.hxh.entity.ProjectTableFiledConfig;
import com.hxh.entity.ProjectTablePageConfig;
import com.hxh.entity.po.ClassInfo;
import com.hxh.entity.po.CreateTableSql;
import com.hxh.entity.po.FieldName;
import com.hxh.generater.springBoot.GenerationTableInfo;
import com.hxh.generater.springBoot.util.methodParse.ParseJavaMethod;
import com.hxh.generater.springBoot.util.methodParse.entity.JavaClassMethod;
import com.hxh.generater.vue.simple.gen.GenSimpleVue;
import com.hxh.service.ProjectTableFiledConfigService;
import com.hxh.service.ProjectTablePageConfigService;
import com.hxh.util.GenUtil;
import com.hxh.util.MysqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.hxh.config.Constants.ProjectDirSuffix;

@Slf4j
public class GenSimpleHistoryTable {
    /**
     * 生成历史记录表SQL
     *
     * @param project
     * @param classInfo
     * @return
     * @throws Exception
     */
    public String generationHistoryTableSql(Project project, ClassInfo classInfo, String charset) throws Exception {
        if (StringUtils.isBlank(charset)) {
            charset = "gbk";
        }
        ProjectDatasource projectDatasource = project.getProjectDatasource();
        String tableName = classInfo.getTableName();
        List<CreateTableSql> createTableSqlList = MysqlUtils.executeOneQuery(projectDatasource, "show create table " + tableName, CreateTableSql.class);
        if (CollectionUtils.isEmpty(createTableSqlList)) {
            throw new RuntimeException("获取表:" + tableName + "的建表语句失败");
        }
        CreateTableSql createTableSql = createTableSqlList.get(0);
        String oriSql = createTableSql.getSql();
        List<String> oriSqlList = new ArrayList<>(Arrays.asList(oriSql.split("\n")));

        List<FieldName> idNameList = classInfo.getIdNameList();


        StringBuilder sql = new StringBuilder();
        sql.append("CREATE TABLE `" + tableName + "_history` (\n");
        sql.append("  `history_id` int NOT NULL AUTO_INCREMENT COMMENT '历史记录表ID',\n");


        for (String perSql : oriSqlList) {
            String temp = perSql.trim();
            for (FieldName fieldName : idNameList) {
                if (temp.startsWith("`" + fieldName.getName() + "` ")) {
                    temp = temp.replace("AUTO_INCREMENT", "");
                    sql.append(temp).append("\n");
                }
            }
        }
        sql.append(" `update_content` VARCHAR(2048) NULL DEFAULT NULL COMMENT '修改内容',\n");
        sql.append(" `updater` VARCHAR(32) NULL DEFAULT NULL COMMENT '修改人',\n");
        sql.append(" `create_time` DATETIME NULL DEFAULT NULL COMMENT '修改时间',\n");
        sql.append("  PRIMARY KEY (`history_id`) USING BTREE\n");
        sql.append(") ENGINE=InnoDB DEFAULT CHARSET=" + charset + " ROW_FORMAT=DYNAMIC COMMENT='" + classInfo.getDesc() + "-历史记录表'");
        return sql.toString();
    }

    /**
     * @param project:
     * @param classInfo:
     * @return void
     * @author HXH
     * @description: 寻找service的update方法，加上注解HistoryAnnotation
     * @date 2024/5/24
     **/
    private static void addHistoryAnnotation(Project project, ClassInfo classInfo) throws Exception {
        String serviceName = classInfo.getClassName() + "Service";
        String pathPre = project.getBackendProject().getProjectDir() + project.getBackendProject().getProjectName() + "\\" + ProjectDirSuffix + "\\"
                + project.getBackendProject().getProjectGroup().replaceAll("\\.", "\\\\\\\\");
        String filePath = pathPre + "\\service\\" + serviceName + ".java";
        File oldFile = new File(filePath);
        if (!oldFile.exists()) {
            throw new RuntimeException("添加历史记录注解失败，类不存在！" + filePath);
        }
        List<JavaClassMethod> javaClassMethodList = ParseJavaMethod.parser(oldFile);
        List<Integer> updateMethodStartLine = new ArrayList<>();
        for (JavaClassMethod javaClassMethod : javaClassMethodList) {
            if ("update".equals(javaClassMethod.getMethodName())) {
                updateMethodStartLine.add(javaClassMethod.getStartLine());
            }
        }
        if (CollectionUtils.isEmpty(updateMethodStartLine)) {
            throw new RuntimeException("添加历史记录注解失败，不存在update方法！");
        }
        File newFile = GenUtil.newFile(project, "service", serviceName);
        oldFile = new File(pathPre + "\\service\\" + serviceName + ".java.bak");


        StringBuilder ids = new StringBuilder("{");

        for (FieldName fieldName : classInfo.getIdNameList()) {
            ids.append("\"").append(fieldName.getJavaName()).append("\",");
        }
        if (ids.length() > 1) {
            ids.deleteCharAt(ids.length() - 1);
        }
        ids.append("}");

        try (FileWriter fileWriter = new FileWriter(newFile);
             BufferedWriter writer = new BufferedWriter(fileWriter);
             BufferedReader br = new BufferedReader(new FileReader(oldFile))) {
            String line;

            int currentLine = 0;
            int updateMethodStartLineIndex = 0;
            int updateMethodStartLineMaxLen = updateMethodStartLine.size();
            boolean hasAnnotation = false;
            boolean hasImportHistoryAnnotation = false;
            while ((line = br.readLine()) != null) {
                currentLine++;

                if (currentLine == 3 && !hasImportHistoryAnnotation && !line.contains("HistoryAnnotation")) {
                    line = "import " + project.getBackendProject().getProjectGroup() + ".annotation.HistoryAnnotation;\n" + line;
                }
                if (StringUtils.isNotBlank(line)) {
                    if (line.contains("HistoryAnnotation")) {
                        if (hasImportHistoryAnnotation) {
                            line = "";
                        }
                        hasImportHistoryAnnotation = true;
                    }
                    if (updateMethodStartLineIndex < updateMethodStartLineMaxLen) {
                        int listStartLine = updateMethodStartLine.get(updateMethodStartLineIndex);
                        if (currentLine == listStartLine && !hasAnnotation) {
                            line = "    @HistoryAnnotation(ids = " + ids + ")\n" + line;
                            updateMethodStartLineIndex++;
                        } else if (currentLine + 3 >= listStartLine) {
                            //如果之前已经被加过注解了，就不加了
                            if (line.contains("@HistoryAnnotation")) {
                                hasAnnotation = true;
                            }
                        } else {
                            //之前没加过
                            hasAnnotation = false;
                        }
                    }
                    writer.write(line);
                }
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理生成历史记录表的逻辑
     *
     * @param project
     * @param classInfo
     * @throws IOException
     */
    public void process(Project project, ClassInfo classInfo) throws Exception {
        String tableName = classInfo.getTableName();
        //建表
        String sql = generationHistoryTableSql(project, classInfo, null);
        ProjectDatasource classInfoProjectDatasource = classInfo.getProjectDatasource();
        MysqlUtils.executeOneSql(classInfoProjectDatasource, sql);
        Thread.sleep(100);

        //处理字段映射
        String historyTableName = tableName + "_history";
        ProjectTableFiledConfig projectTableFiledConfig = new ProjectTableFiledConfig();
        projectTableFiledConfig.setProjectId(project.getId());
        projectTableFiledConfig.setTableName(historyTableName);
        projectTableFiledConfig.setFiledName("update_content");
        projectTableFiledConfig.setDatasourceId(classInfoProjectDatasource.getId());
        ProjectTableFiledConfigService projectTableFiledConfigService = ApplicationContextUtil.getOneBeanByType(ProjectTableFiledConfigService.class);
        List<ProjectTableFiledConfig> list = projectTableFiledConfigService.select(projectTableFiledConfig);
        if (CollectionUtils.isEmpty(list)) {
            projectTableFiledConfig.setShowName("修改内容");
            projectTableFiledConfig.setShowType("textarea");
            projectTableFiledConfig.setId(null);
            projectTableFiledConfigService.insert(projectTableFiledConfig);
        }
        List<FieldName> idNameList = classInfo.getIdNameList();
        StringBuilder primaryKeys = new StringBuilder();
        for (FieldName fieldName : idNameList) {
            primaryKeys.append(fieldName.getName()).append(",");
            //处理原id映射
            projectTableFiledConfig.setFiledName(fieldName.getName());
            list = projectTableFiledConfigService.select(projectTableFiledConfig);
            if (CollectionUtils.isEmpty(list)) {
//                String showName = fieldName.getDesc();
//                ProjectTableFiledConfig pfc = fieldName.getProjectTableFiledConfig();
//                if (pfc != null) {
//                    showName = pfc.getShowName();
//                }
//                projectTableFiledConfig.setShowName("原记录" + showName);
                projectTableFiledConfig.setShowName("原记录ID");
                projectTableFiledConfig.setShowType("text");
                projectTableFiledConfig.setId(null);
                projectTableFiledConfigService.insert(projectTableFiledConfig);
            }
        }
        //页面配置
        ProjectTablePageConfigService projectTablePageConfigService = ApplicationContextUtil.getOneBeanByType(ProjectTablePageConfigService.class);

        ProjectTablePageConfig projectTablePageConfig = new ProjectTablePageConfig();
        projectTablePageConfig.setProjectId(project.getId());
        projectTablePageConfig.setTableName(historyTableName);
        List<ProjectTablePageConfig> projectTablePageConfigList = projectTablePageConfigService.select(projectTablePageConfig);
        if (CollectionUtils.isEmpty(projectTablePageConfigList)) {
            projectTablePageConfig.setSearchFields("updater");
            projectTablePageConfig.setTableColumnFields(primaryKeys + "update_content,updater,create_time");
            projectTablePageConfig.setShowAdd("0");
            projectTablePageConfig.setShowDelete("0");
            projectTablePageConfig.setShowUpdate("0");
            projectTablePageConfig.setDatasourceId(classInfoProjectDatasource.getId());
            projectTablePageConfigService.insert(projectTablePageConfig);
        }
        //生成crud
        ClassInfo historyClassInfo = GenerationTableInfo.getTableInfo(project, null, historyTableName);

        GenSimpleTableCRUD genSimpleTableCRUD = new GenSimpleTableCRUD();
        genSimpleTableCRUD.generationServiceImplClass(project, historyClassInfo);
        genSimpleTableCRUD.generationEntity(project, historyClassInfo);
        genSimpleTableCRUD.generationDaoClass(project, historyClassInfo);
        genSimpleTableCRUD.generationMapper(project, historyClassInfo);
        genSimpleTableCRUD.generationControllerClass(project, historyClassInfo);

        //vue
        GenSimpleVue genSimpleVue = new GenSimpleVue();
        genSimpleVue.generationView(project, historyClassInfo);
        genSimpleVue.generationApi(project, historyClassInfo);

        //添加菜单
        GenSimpleTableMenu genSimpleTableMenu = new GenSimpleTableMenu();
        genSimpleTableMenu.initTableMenu(project, historyClassInfo);

        addHistoryAnnotation(project, classInfo);

    }

}
